package com.dz.tool.Utils;

import com.dz.tool.Vo.HibernateInfo;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;

public class XMLUtils {

    private static final Map<String, Document> cacheDocument = new HashMap<>();
    private static final Map<String, List<HibernateInfo>> cacheHibernateInfoMap = new HashMap<>();

    public static Document getDocument(String path, InputStream fileInput) throws Exception {
        Document document = cacheDocument.get(path);
        // 从缓存中拿，如果没有，创建一个，放入缓存中
        if (document == null) {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            document = db.parse(fileInput);
            cacheDocument.put(path, document);
        }
        return document;
    }

    public static List<String> getTableNameFromHibernateXML(String path) throws Exception {
        System.out.println("开始解析XML文件-" + path);
        //InputStream input = XMLUtils.class.getClassLoader().getResourceAsStream(path);
        InputStream input = new FileInputStream(path);
        Map<String, String> tableMap = new HashMap<>();
        List<String> linkedList = new LinkedList();


        try {
            Document document = getDocument(path, input);
            Element documentElement = document.getDocumentElement();
            NodeList childNodes = documentElement.getElementsByTagName("class");
            Element element = (Element) childNodes.item(0);
            String table = element.getAttribute("table");
            String className = element.getAttribute("name");
            className = className.substring(className.lastIndexOf(".") + 1);
            tableMap.put(className, table);
            linkedList.add(className);
            linkedList.add(table);
            linkedList.add(path);
            if (!StringUtils.hasLength(table)) {
                throw new Exception("传入的不是xml映射文件");
            }
//            System.out.println("解析完毕-" + className + "===" + table);
            return linkedList;
        } catch (Exception e) {
            throw e;
        } finally {
            close(input);
        }
    }

    public static List<HibernateInfo> getHibernateCache(String path) throws Exception {
        try {
            loadHibernateFile(path);
            List<HibernateInfo> list = cacheHibernateInfoMap.get(path);
            return list;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 只会将hibernate中存在的字段加入缓存，VO中存在但hibernate不存在的字段，不会加入缓存
     *
     * @param path
     * @throws Exception
     */
    public static void loadHibernateFile(String path) throws Exception {
        // 如果已经load过，则无需load
        List<HibernateInfo> list = cacheHibernateInfoMap.get(path);
        if (list != null) {
            return;
        }

        InputStream input = new FileInputStream(path);
        boolean flag = false;
        try {
            // id为单独主键 composite-id为联合主键
            String primaryType = null;

            Document document = getDocument(path, input);
            Element documentElement = document.getDocumentElement();

            // 主键字段 load到缓存
            NodeList compositeId = documentElement.getElementsByTagName("composite-id");
            if (compositeId.getLength() > 0) {
                primaryType = "composite-id";
                for (int i = 0; i < compositeId.getLength(); i++) {
                    Element element = (Element) compositeId.item(i);
                    NodeList keyPropertys = element.getElementsByTagName("key-property");
                    if (keyPropertys.getLength() > 0) {
                        for (int j = 0; j < keyPropertys.getLength(); j++) {
                            Element keyProperty = (Element) keyPropertys.item(j);
                            String field = keyProperty.getAttribute("name");
                            String column = keyProperty.getAttribute("column");
                            if (!StringUtils.hasLength(column)) {
                                NodeList columns = element.getElementsByTagName("column");
                                if(columns.getLength() > 0){
                                    for (int k = 0; k < columns.getLength(); k++) {
                                        Element clmElement = (Element) columns.item(k);
                                        column = clmElement.getAttribute("name");
                                    }
                                }
                            }
                            HibernateInfo hi = new HibernateInfo(path, true, primaryType, field, column, null);
                            loadHibernateFile(hi);
                        }
                    }
                }
            }
            // 主键字段 load到缓存
            NodeList id = documentElement.getElementsByTagName("id");
            if (id.getLength() > 0) {
                primaryType = "id";
                for (int i = 0; i < id.getLength(); i++) {
                    Element element = (Element) id.item(i);
                    String field = element.getAttribute("name");
                    String column = element.getAttribute("column");
                    if (!StringUtils.hasLength(column)) {
                        NodeList columns = element.getElementsByTagName("column");
                        if(columns.getLength() > 0){
                            for (int k = 0; k < columns.getLength(); k++) {
                                Element clmElement = (Element) columns.item(k);
                                column = clmElement.getAttribute("name");
                            }
                        }
                    }
                    String generatorType = null;
                    NodeList generators = element.getElementsByTagName("generator");
                    if(generators.getLength() > 0){
                        for (int k = 0; k < generators.getLength(); k++) {
                            Element generator = (Element) generators.item(k);
                            generatorType = generator.getAttribute("class");
                        }
                    }
                    HibernateInfo hi = new HibernateInfo(path, true, primaryType, field, column, generatorType);
                    loadHibernateFile(hi);
                }
            }

            if (!StringUtils.hasLength(primaryType)) {
                System.out.println("主键检查-----此表无主键，请检查，path：" + path);
            }

            // 非主键字段 load到缓存
            NodeList propertys = documentElement.getElementsByTagName("property");
            primaryType = null;
            if (propertys.getLength() > 0) {
                for (int i = 0; i < propertys.getLength(); i++) {
                    Element element = (Element) propertys.item(i);
                    String field = element.getAttribute("name");
                    String column = element.getAttribute("column");
                    if (!StringUtils.hasLength(column)) {
                        NodeList columnList = element.getElementsByTagName("column");
                        if (columnList.getLength() > 0) {
                            for (int j = 0; j < columnList.getLength(); j++) {
                                Element colElement = (Element) columnList.item(j);
                                column = colElement.getAttribute("name");
                                HibernateInfo hi = new HibernateInfo(path, false, primaryType, field, column, null);
                                loadHibernateFile(hi);
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            throw e;
        } finally {
            close(input);
        }
    }

    private static void loadHibernateFile(HibernateInfo hi) throws Exception {
        String path = hi.getPath();
        String fieldName = hi.getFieldName();
        String tableFiledName = hi.getTableFiledName();
        String errorMsg = "loadHibernateFile 报错了-path:" + path + " fieldName:" + fieldName + " tableFiledName:" + tableFiledName;
        if (!StringUtils.hasLength(path) || !StringUtils.hasLength(fieldName) || !StringUtils.hasLength(tableFiledName)) {
            throw new Exception(errorMsg);
        }

        List<HibernateInfo> hibernateInfos = cacheHibernateInfoMap.get(path);
        if (hibernateInfos == null) {
            hibernateInfos = new ArrayList<>();
            hibernateInfos.add(hi);
            cacheHibernateInfoMap.put(path, hibernateInfos);
        } else {
            hibernateInfos.add(hi);
        }
    }

    public static void close(Closeable closeable) throws Exception {
        if (null != closeable) {
            closeable.close();
        }
    }


    public static void main(String[] args) throws Exception {
        getHibernateCache("E:\\A\\OrgDptVO.hbm.xml");
    }
}

